﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Autofac;
using Web7.Ioc;
using System.Configuration;
using Web7.Core.Configuration;
using Web7.Configuration;
using System.Web.Routing;
using System.Web.Hosting;
using Web7.Core.Apps;
using Web7.RouteUrlModifiers;
using Web7.Core.Sites;
using Web7.Caching;

namespace Web7.Core.IOC.Autofac
{
    public class AutofacDependencyInjector : IDependencyInjector, IDependencyResolver
    {
        private readonly IContainer _container;
        private readonly ContainerBuilder _containerBuilder;

        public AutofacDependencyInjector()
        {
            _containerBuilder = new ContainerBuilder();

            //todo:注册一堆系统的东西
            RegisterContainer();

            // 将自身注册为单例
            _containerBuilder.RegisterInstance<IDependencyInjector>(this).SingleInstance();
            _containerBuilder.RegisterInstance<IDependencyResolver>(this).SingleInstance();
            _container = _containerBuilder.Build();
        }

        #region Method
        static bool TryResolveAtScope(ILifetimeScope scope, Type serviceType, out object value)
        {
            if (scope == null)
            {
                value = null;
                return false;
            }
            return scope.TryResolve(serviceType, out value);
        }

        bool TryResolve(Type serviceType, out object value)
        {
            return TryResolveAtScope(_container, serviceType, out value);
        }

        static object CreateInstance(Type t)
        {
            if (t.IsAbstract || t.IsInterface)
                return null;

            return Activator.CreateInstance(t);
        }

        TService Resolve<TService>(Type serviceType, TService defaultValue = default(TService))
        {
            object value;
            return TryResolve(serviceType, out value) ? (TService)value : defaultValue;
        }

        TService Resolve<TService>(Type serviceType, Func<Type, TService> defaultFactory)
        {
            object value;
            return TryResolve(serviceType, out value) ? (TService)value : defaultFactory(serviceType);
        }
        #endregion


        #region IDependencyResolver
        object IDependencyResolver.GetService(Type serviceType)
        {
            // Resolve service, or null
            return Resolve(serviceType, default(object));
        }

        IEnumerable<object> IDependencyResolver.GetServices(Type serviceType)
        {
            return Resolve<IEnumerable>(typeof(IEnumerable<>).MakeGenericType(serviceType), Enumerable.Empty<object>()).Cast<object>();
        }
        #endregion


        #region IDependencyInjector
        IDependencyInjector IDependencyInjector.RegisterInstance<T>(T instance)
        {
            if (CanResolve(typeof(T)))
            {
                _containerBuilder.RegisterInstance(instance);
            }
            return this;
        }

        IDependencyInjector IDependencyInjector.RegisterInstance<TFrom, TTo>()
        {
            if (CanResolve(typeof(TFrom)))
            {
                _containerBuilder.RegisterType<TFrom>().As<TTo>();
            }
            return this;
        }

        IDependencyInjector IDependencyInjector.RegisterInstance(Type from, Type to)
        {
            if (CanResolve(from))
            {
                _containerBuilder.RegisterType(from).As(to);
            }
            return this;
        }

        IDependencyInjector IDependencyInjector.RegisterType<TFrom, TTo>()
        {
            if (CanResolve(typeof(TFrom)))
            {
                _containerBuilder.RegisterType<TFrom>().As<TTo>();
            }
            return this;
        }

        IDependencyInjector IDependencyInjector.RegisterType(Type from, Type to)
        {
            if (CanResolve(from))
            {
                _containerBuilder.RegisterType(from).As(to);
            }
            return this;
        }

        IDependencyInjector IDependencyInjector.RegisterAssembly(params System.Reflection.Assembly[] assemblies)
        {
            if (assemblies != null)
            {
                foreach (var assembly in assemblies)
                {
                    var list = from t in assembly.GetTypes()
                               where t.IsClass
                                    && !t.IsAbstract
                                    && typeof(IDependency).IsAssignableFrom(t)
                               select t;

                    foreach (var t in list)
                    {
                        var interfaces = t.GetInterfaces()
                                        .Where(m => typeof(IDependency)
                                        .IsAssignableFrom(m))
                                        .ToList();

                        foreach (var IType in interfaces)
                        {
                            //todo:需要测试例如单例之流的东西
                            _containerBuilder.RegisterType(t).As(IType);
                        }
                    }
                }
            }
            return this;
        }

        T IDependencyInjector.Inject<T>(T existing)
        {
            //if (CanResolve(typeof(T)))
            //{
            //    _containerBuilder.RegisterInstance(existing).
            //}
            //return null;
            throw new NotImplementedException();
        }

        T IDependencyInjector.GetService<T>()
        {
            // Resolve service, or null
            return Resolve(typeof(T), default(T));
        }

        IT IDependencyInjector.GetService<IT, T>()
        {
            return (IT)Resolve<object>(typeof(T), default(T));
        }

        object IDependencyInjector.GetService(Type serviceType)
        {
            // Resolve service, or null
            return Resolve(serviceType, default(object));
        }

        IEnumerable<object> IDependencyInjector.GetServices(Type serviceType)
        {
            return Resolve<IEnumerable>(typeof(IEnumerable<>).MakeGenericType(serviceType), Enumerable.Empty<object>()).Cast<object>();
        }

        bool IDependencyInjector.IsRegistered<T>()
        {
            return _container.IsRegistered<T>();
        }

        public bool IsRegistered(Type type)
        {
            return _container.IsRegistered(type);
        }

        bool IDependencyInjector.CanResolve<T>()
        {
            return CanResolve(typeof(T));
        }

        public bool CanResolve(Type type)
        {
            if (isResolvableClass(type))
                return true;
            return IsRegistered(type);
        }

        private bool isResolvableClass(Type type)
        {
            return type.IsClass && !type.IsAbstract;
        }

        #endregion

        protected void RegisterContainer()
        {
            //// 注册已有对象实例为单例
            _containerBuilder
                // Web7ConfigurationSection为自定义配置节点，用于配置Module信息
                .RegisterInstance((Web7ConfigurationSection)ConfigurationManager.GetSection("web7")).SingleInstance();
            // AppSettingsHelper对web.config的appSettings节点进行封装
            _containerBuilder.RegisterInstance(new AppSettingsHelper(ConfigurationManager.AppSettings)).SingleInstance();
            // IDependencyResolver
            //.RegisterInstance(DependencyResolver.Current)
            // RouteCollection，全局的静态的路由表
            _containerBuilder.Register(x => RouteTable.Routes).SingleInstance();
            // ModelBinderDictionary，通过请求数据(QueryString、Form、RouteValue等)生成实体
            _containerBuilder.Register(x => ModelBinders.Binders).SingleInstance();
            // ViewEngineCollection，视图引擎集合
            _containerBuilder.Register(x => ViewEngines.Engines).SingleInstance();
            // GlobalFilterCollection，全局拦截器集合，本身也是拦截器提供器
            _containerBuilder.Register(x => GlobalFilters.Filters).SingleInstance();
            // FilterProviderCollection 拦截器提供器集合
            _containerBuilder.Register(ctx => System.Web.Mvc.FilterProviders.Providers).SingleInstance();
            // VirtualPathProvider 虚拟路径提供器
            _containerBuilder.Register(x => HostingEnvironment.VirtualPathProvider).SingleInstance();

            // ModulesLoaded 相当于一个容器类，用于加载指定模块(Module)，并用一个集合保存之
            _containerBuilder.RegisterInstance<IAppRegistry>(new AppRegistry(this)).SingleInstance();

            // FilterRegistryFilterProvider Filter注册表Filter提供器
            //_containerBuilder.RegisterInstance(new FilterRegistryFilterProvider(this)).SingleInstance();

            // LoadModules引导程序，根据Web7.config中modules节点的配置，对模块进行注册
            // LoadBackgroundServices引导程序，加载后台服务
            //_containerBuilder.RegisterInstance<IBootStrapperTask>(new LoadApps(this)).SingleInstance(); //"LoadApps",
            //_containerBuilder.RegisterInstance<IBootStrapperTask>(new LoadBackgroundServices(this)).SingleInstance();//"LoadBackgroundServices",

            //注册缓存
            _containerBuilder.Register<ICacheManager>(x => DefaultCacheManager.Instance()).SingleInstance();

            // RouteUrlModifier 用于给Route路径加前缀(目的是为了兼容默认配置下的IIS5.1以及IIS6)
            _containerBuilder.RegisterType<RouteUrlModifier>().As<IRouteUrlModifier>();

            _containerBuilder
                // 系统(站点)配置信息处理逻辑
            .RegisterType<SiteService>().As<ISiteService>();

            // 自定义Site生命周期。当需要注入Site对象时，首先尝试从当前HttpContextState中获取，如果为null则从其他途径获取(缓存或数据库等)
            //.RegisterType<Site>(new FactoryMethodLifetimeManager(() => HttpContext.Current.Items[typeof(Site).FullName] as Site ?? childContainer.Resolve<ISiteService>().GetItem()))
            //.RegisterType<IUser>(new FactoryMethodLifetimeManager(() => HttpContext.Current.Items[typeof(IUser).FullName] as IUser ?? new UserAnonymous()))
            //.RegisterType<IAuthenticationApp>(new FactoryMethodLifetimeManager(() => HttpContext.Current.Items[typeof(IAuthenticationApp).FullName] as IAuthenticationApp ?? null))
            //.RegisterType<RequestContext>(new FactoryMethodLifetimeManager(() => HttpContext.Current.Items[typeof(RequestContext).FullName] as RequestContext ?? new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData())));          
        }
    }
}
